package xcore

import (
	"context"
	"fmt"
	"gitee.com/xfrm/middleware/xlog"
	"time"
)

//尝试执行，如果成功结束，否则继续尝试。
// totalTimes 最大尝试次数
// intervalMs 暂停的时长毫秒数。是个数组 第一次失败后暂停[0]的毫秒，第二次暂停[1]毫秒依次类推，数组到头之后从0开始
// executor需要执行的操作，返回error则认为失败
// 返回结果中 如果 error不为空 则表示一直没有成功。否则最终执行成功了，int表示第几次执行成功，如果为1 ，表示没有失败过。
func Try(ctx context.Context, totalTimes int, intervalMs []int, executor func(ctx context.Context, ctimes int) error) (int, error) {
	if len(intervalMs) < 1 {
		intervalMs = []int{500}
	}
	if totalTimes <= 0 {
		totalTimes = 1
	}
	var times = 0
	var err error
	for {
		if times < totalTimes {
			err = executor(ctx, times+1)
			if err != nil {
				time.Sleep(time.Duration(intervalMs[times%len(intervalMs)]) * time.Millisecond)
				times++
			} else {
				return times + 1, nil
			}
		} else {
			return times + 1, err
		}
	}
	return times + 1, err
}

var exitError = fmt.Errorf("exits")

//间歇性执行
//interval 是tickal, 因此interval是不变的
func TickExecute(ctx context.Context, interval time.Duration, stopWhenError bool, executor func(ctx context.Context) error) {
	defer func() {
		if r := recover(); r != nil {
			xlog.Errorf(ctx, "recover from panic %v", r)
		}
	}()
	exe := func() error {
		select {
		case <-ctx.Done():
			xlog.Infof(ctx, "ctx done")
			return exitError
		default:
			if err := executor(ctx); err != nil {
				xlog.Infof(ctx, " executor error: %v", err)
				if stopWhenError {
					return exitError
				}
			}
		}
		return nil
	}
	if interval > 0 {
		ticker := time.Tick(interval)
		for range ticker {
			if err := exe(); err == exitError {
				return
			}
		}
		return
	}
	for {
		if err := exe(); err == exitError {
			return
		}
	}
}

//间隔多久执行一次
//注意intervalFun可以动态修改
func IntervalExecute(ctx context.Context, intervalFun func(ctx2 context.Context) time.Duration, stopWhenError bool, executor func(ctx context.Context) error) {
	TickExecute(ctx, 0, stopWhenError, func(ctx context.Context) error {
		defer time.Sleep(intervalFun(ctx))
		err := executor(ctx)
		if err != nil {
			return err
		}
		return nil
	})
}
